Skip to content

fix(image): 修复图片上传 — token 解析与 OSS 文件 Content-Type#5

Open
kay120 wants to merge 1 commit into
iswalle:mainfrom
kay120:fix/image-upload-token-parsing
Open

fix(image): 修复图片上传 — token 解析与 OSS 文件 Content-Type#5
kay120 wants to merge 1 commit into
iswalle:mainfrom
kay120:fix/image-upload-token-parsing

Conversation

@kay120

@kay120 kay120 commented May 29, 2026

Copy link
Copy Markdown

问题 / Problem

getnote save <image> 保存图片笔记时,任何图片都失败,报错:

Error: no upload token returned

复现:@getnote/cli@1.1.8(npm 最新),getnote save ./any.png。文字/链接笔记正常,唯独图片失败。

根因 / Root cause

实测发现是两处独立的 bug,第二处在修复第一处后才会暴露:

Bug 1 — upload token 响应解析

GET /open/api/v1/resource/image/upload_token 服务端实际返回的 data单个 token 对象

{"success":true,"data":{"accessid":"LTAI...","host":"https://...oss...","policy":"...","signature":"...","callback":"...","object_key":"...","access_url":"...","oss_content_type":"image/png"}}

但客户端把它当成 { "tokens": [ ... ] } 来解析(ImageUploadTokenData.Tokens []ImageUploadToken),导致 Tokens 永远为空,于是 len(...Tokens)==0no upload token returned

Bug 2 — OSS 文件 part 的 Content-Type

修好 Bug 1 后,上传到 OSS 仍 403:

OSS upload error 403: Invalid according to Policy: Policy Condition failed:
["eq", "$Content-Type", "image/png"]
ExecCondition: ["eq", "application/octet-stream", "image/png"]

multipart.CreateFormFile 会把文件 part 的 Content-Type 硬编码成 application/octet-stream,违反 OSS 上传策略里 ["eq","$Content-Type","image/png"] 的条件。需把文件 part 的 Content-Type 显式设为 token 的 oss_content_type

修改 / Changes

  • internal/client/client.goImageUploadTokenResponse.Data 改为单个 ImageUploadToken(移除多余的 ImageUploadTokenData 包装层)。
  • cmd/save/save.go:相应改用 tokenResp.Data,并以 AccessID/Policy 非空作为有效性判断。
  • internal/client/client.goImageUploadToOSSCreatePart 显式设置文件 part 的 Content-Typeoss_content_type,替代 CreateFormFile

验证 / Verification

本地 go build ./... + go vet ./... 通过,并用真实 API key 端到端实测。完整对照(文本复现):

# ── 修复前:官方 v1.1.8(npm 最新)──────────────────────────
$ getnote save image.png
Error: no upload token returned

# ── 直接打 token 接口,确认服务端其实返回了有效 token ─────────
$ curl -sG https://openapi.biji.com/open/api/v1/resource/image/upload_token \
       -H "Authorization: Bearer $KEY" -H "X-Client-ID: $CID" \
       --data-urlencode "mime_type=image/png" --data-urlencode "count=1"
{"success":true,"data":{"accessid":"LTAI...","host":"https://...oss-accelerate.aliyuncs.com",
 "policy":"...","signature":"...","callback":"...","object_key":"...",
 "access_url":"https://...","oss_content_type":"image/png"}}
#  ↑ data 是单个对象,没有 tokens 数组 → 旧代码 len(Data.Tokens)==0 → "no upload token returned"

# ── 修复后:本分支编译的二进制 ──────────────────────────────
$ getnote save image.png
Uploading image.png...
✓ Saving... (task_id: 6a1a2428...)
... done
  ID    | 1911365767908164272
  Type  | img_text
  Title | (服务端自动 OCR 生成)

注:仅修复 Bug 1 后,OSS POST 会暴露 Bug 2 的 403(Policy Condition failed: ["eq", "$Content-Type", "image/png"],实际送出的是 application/octet-stream)。两处都修后才端到端打通。

相关:与 #1(packaged binaries / 解析与服务端 API 漂移)属同类问题。

The /resource/image/upload_token API returns the token object directly
under `data`, but the client expected `data.tokens[]`, so the slice was
always empty and image saves failed with "no upload token returned".

After fixing the parsing, the OSS POST still failed with 403 because
multipart.CreateFormFile hardcodes the file part Content-Type to
application/octet-stream, violating the upload policy condition
(`["eq", "$Content-Type", "image/png"]`). Set the file part
Content-Type explicitly to the token's oss_content_type.

Verified end-to-end against the live API: image note now uploads and saves.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant